import * as ts from 'typescript';
import { errors } from '../errors';
import * as fs from 'fs';
import * as path from 'path';
import { ProjectCompiler } from '../project-compiler';

const TS_CONFIG_FILE = 'tsconfig.json';

type TypeScriptProjectConfig = {
    compilerOptions: ts.CompilerOptions;
}

/** 
 * 编译特定文件，并生成到制定目录 
 * @param filePath 源文件路径，绝对路径
 * @param outDir 输出目录，相对于项目路径
 * @param projectPath 项目路径，绝对路径
 * */
export async function compileFile(filePath: string, outDir: string, projectPath: string) {
    if (!filePath)
        throw errors.argumentNull('sourcePath');
    if (!outDir)
        throw errors.argumentNull('outDir');
    if (!projectPath)
        throw errors.argumentNull('projectPath');

    if (!path.isAbsolute(filePath))
        throw errors.notAbsolutePath(filePath);


    let content = fs.readFileSync(filePath, 'utf-8');
    let compilerOptions = getTypescriptConfig(projectPath, path.dirname(filePath));
    let result = ts.transpileModule(content, { compilerOptions });

    console.log(result.outputText);

    let ext = path.extname(filePath);
    let outExt = ProjectCompiler.tsOutExt;
    let targetPath = path.join(projectPath, outDir, path.basename(filePath).replace(ext, outExt));
    let outDirPath = path.resolve(targetPath, "..");

    if (!fs.existsSync(outDirPath))
        fs.mkdirSync(outDirPath, { recursive: true });

    fs.writeFileSync(targetPath, result.outputText);
}

export function getTypescriptConfig(projectPath: string, directoryPath: string): ts.CompilerOptions {
    let configPath = findTypeScriptConfigPath(projectPath, directoryPath);
    let compilerOptions: ts.CompilerOptions;
    if (!configPath) {
        compilerOptions = defaultCompilerOptions();
    }
    else {
        let configContent = fs.readFileSync(configPath, 'utf-8');
        let config = JSON.parse(configContent) as TypeScriptProjectConfig;
        compilerOptions = config.compilerOptions;
    }

    return compilerOptions;
}

export function findTypeScriptConfigPath(projectPath: string, directoryPath: string): string | null {
    if (!path.isAbsolute(directoryPath)) {
        directoryPath = path.join(projectPath, directoryPath);
    }

    console.assert(path.isAbsolute(projectPath), `projectPath ${projectPath} is not absolute`);
    console.assert(path.isAbsolute(directoryPath), `directoryPath ${directoryPath} is not absolute`);
    let tsConfigPath = path.join(directoryPath, TS_CONFIG_FILE);

    if (fs.existsSync(tsConfigPath)) {
        return tsConfigPath;
    }

    if (projectPath == directoryPath)
        return null;

    let parentPath = path.resolve(directoryPath, "..");

    return findTypeScriptConfigPath(projectPath, parentPath);
}

function defaultCompilerOptions(): ts.CompilerOptions {
    let r: ts.CompilerOptions = {
        module: ts.ModuleKind.CommonJS,
        target: ts.ScriptTarget.ESNext,
    }

    return r;
}